package com.zc.im.connector.starter;

import com.zc.im.common.constant.RegisterInfoConstant;
import com.zc.im.common.util.IpUtil;
import com.zc.im.connector.init.ImChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * Project：im
 * Date：2022/4/21
 * Time：11:25
 * Description：服务启动器
 *
 * @author Challen.Zhang
 * @version 1.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ServerStarter {

    private final ImChannelInitializer imChannelInitializer;

    private final CuratorFramework curatorClient;

    private EventLoopGroup bossGroup;

    private EventLoopGroup workerGroup;

    private Channel channel;

    public void start(int port) {
        bossGroup = new NioEventLoopGroup(2);
        workerGroup = new NioEventLoopGroup();
        try {
            //创建服务器端的启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            //使用链式编程来配置参数
            //设置两个线程组
            bootstrap.group(bossGroup, workerGroup)
                    //使用NioServerSocketChannel作为服务器的通道实现
                    .channel(NioServerSocketChannel.class)
                    // 初始化服务器连接队列大小，服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接。
                    // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(imChannelInitializer);
            ChannelFuture cf = bootstrap.bind(port).sync();
            //给cf注册监听器，监听我们关心的事件
            cf.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (cf.isSuccess()) {
                        log.info("netty server start success  ... port : [{}]", port);
                        // 注册
                        register(IpUtil.getAddressAndPort());
                    } else {
                        log.info("netty server start fail  ... port : [{}]", port);
                    }
                }
            });
            channel = cf.channel();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @PreDestroy
    public void destroy() {
        if (channel != null) {
            channel.close();
        }
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        offline(IpUtil.getAddressAndPort());
    }

    protected void register(String addressAndPort) {
        try {
            curatorClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(RegisterInfoConstant.REGISTER_PATH + "/" + addressAndPort);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void offline(String addressAndPort) {
    }
}
